<?php

declare(strict_types=1);
/**
 * This file is part of MoChat.
 * @link     https://mo.chat
 * @document https://mochat.wiki
 * @contact  group@mo.chat
 * @license  https://github.com/mochat-cloud/mochat/blob/master/LICENSE
 */
namespace MoChat\Plugin\ChannelCode\Logic\Traits;

use MoChat\App\Corp\Utils\WeWorkFactory;
use MoChat\App\WorkContact\Contract\WorkContactEmployeeContract;
use MoChat\App\WorkEmployee\Contract\WorkEmployeeContract;
use MoChat\Framework\Constants\ErrorCode;
use MoChat\Framework\Exception\CommonException;
use MoChat\Plugin\ChannelCode\Constants\AutoAddFriend;
use MoChat\Plugin\ChannelCode\Constants\Status;
use MoChat\Plugin\ChannelCode\Constants\Type;
use MoChat\Plugin\ChannelCode\Contract\ChannelCodeContract;

trait ChannelCodeTrait
{
    /**
     * 更新渠道码二维码
     */
    public function handleQrCode(array $drainageEmployee, int $autoAddFriend, int $corpId, int $channelCodeId, string $wxConfigId = '')
    {
        // 处理引流成员设置 获取满足条件的员工id
        $employeeIds = $this->handelEmployee($drainageEmployee, $channelCodeId);
        if ($employeeIds === [null] || empty($employeeIds)) {
            throw new CommonException(ErrorCode::INVALID_PARAMS, '引流成员客户已达上限或当前时间没有在线员工，请重新选择引流成员');
        }

        // 获取成员微信id
        $employeeWxUserId = $this->getEmployee($employeeIds);

        if (empty($employeeWxUserId)) {
            throw new CommonException(ErrorCode::INVALID_PARAMS, '引流成员微信不存在，请重新选择引流成员');
        }

        // 生成-配置客户联系「联系我」方式-二维码
        $skipVerify = $autoAddFriend == AutoAddFriend::OPEN ? true : false;

        if (empty($wxConfigId)) {
            $this->createQrCode($corpId, $channelCodeId, $employeeWxUserId, $skipVerify);
        } else {
            $this->updateQrCode($corpId, $channelCodeId, $employeeWxUserId, $skipVerify, $wxConfigId);
        }
    }

    /**
     * 处理引流成员设置.
     * @return array
     */
    private function handelEmployee(array $drainageEmployee, int $channelCodeId)
    {
        $employeeIds = [];
        // 客服人员-全天接待
        if (! empty($drainageEmployee['type']) && $drainageEmployee['type'] === Type::ALL_DAY) {
            $employeeIds = $this->allDay($drainageEmployee, $channelCodeId);
        }
        // 客服人员-分时段接待
        if (! empty($drainageEmployee['type']) && $drainageEmployee['type'] === Type::TIME_PERIOD) {
            $employeeIds = $this->timePeriod($drainageEmployee, $channelCodeId);
        }

        return array_merge($employeeIds);
    }

    /**
     * 客服人员-分时段接待.
     */
    private function timePeriod(array $drainageEmployee, int $channelCodeId): array
    {
        $employeeIds = [];
        $week = date('w');
        $time = date('H:i');
        foreach ($drainageEmployee['timeSlot'] as $item) {
            if (in_array((int) $week, $item['week'], true) && $time >= $item['startTime'] && $time <= $item['endTime']) {
                $employeeIds = empty($employeeIds) ? array_column($item['employees'], 'id') : array_merge($employeeIds, array_column($item['employees'], 'id'));
            }
        }

        // 判断员工添加上限
        if (! empty($employeeIds) && $drainageEmployee['addMax']['status'] === Status::OPEN) {
            // 查询员工已有客户数
            $contactEmployee = make(WorkContactEmployeeContract::class);

            $contactCount = $contactEmployee->countWorkContactEmployeesByEmployeeStateCreateTime($employeeIds, 'channelCode-' . $channelCodeId, date('Y-m-d'));
            if (empty($contactCount)) {
                return $employeeIds;
            }
            // 客户数量
            $contactCountIds = array_column($contactCount, 'employeeId');
            $contactCount = array_column($contactCount, null, 'employeeId');
            $addMax = array_column($drainageEmployee['addMax']['employees'], null, 'id');
            foreach ($employeeIds as &$val) {
                // 超过上限的移除
                if ($contactCount[$val]['total'] >= $addMax[$val]['max'] && in_array($val, $contactCountIds, true)) {
                    unset($val);
                }
            }
            unset($val);
        }
        // 所有使用成员均不可接待，备用员工接待
        if (empty($employeeIds)) {
            $employeeIds = array_column($drainageEmployee['specialPeriod'], 'id');
        }
        return array_merge($employeeIds);
    }

    /**
     * 客服人员-全天接待.
     */
    private function allDay(array $drainageEmployee, int $channelCodeId): array
    {
        $employeeIds = array_column($drainageEmployee['timeFull'], 'id');
        if ($drainageEmployee['addMax']['status'] === Status::OPEN && ! empty($drainageEmployee['addMax']['employees'])) {
            // 查询员工已有客户数
            $contactEmployee = make(WorkContactEmployeeContract::class);

            $contactCount = $contactEmployee->countWorkContactEmployeesByEmployeeStateCreateTime(array_column($drainageEmployee['addMax']['employees'], 'id'), 'channelCode-' . $channelCodeId, date('Y-m-d'));
            if (empty($contactCount)) {
                return $employeeIds;
            }
            // 客户数量
            $contactCountIds = array_column($contactCount, 'employeeId');
            $contactCount = array_column($contactCount, null, 'employeeId');
            $addMax = array_column($drainageEmployee['addMax']['employees'], null, 'id');
            foreach ($employeeIds as &$val) {
                // 超过上限的移除
                if ($contactCount[$val]['total'] >= $addMax[$val]['max'] && in_array($val, $contactCountIds, true)) {
                    unset($val);
                }
            }
            unset($val);
        }
        return array_merge($employeeIds);
    }

    /**
     * 获取成员微信id.
     * @param $employeeIds
     * @return array
     */
    private function getEmployee($employeeIds)
    {
        $workEmployee = make(WorkEmployeeContract::class);

        $res = $workEmployee->getWorkEmployeesById($employeeIds, ['name', 'wx_user_id', 'status']);
        if (empty($res)) {
            return [];
        }

        // 验证员工是否还在职(定时任务)
        foreach ($res as $k => $v) {
            if ($v['status'] !== 1) {
                unset($res[$k]);
//                throw new CommonException(ErrorCode::INVALID_PARAMS, "引流成员{$v['name']}未激活或已离职，请重新选择引流成员");
            }
        }
        if (empty($res)) {
            return [];
        }
        return array_column($res, 'wxUserId');
    }

    /**
     * 获取员工已持有客户数.
     * @param $employeeIds
     * @return array
     */
    private function countContact($employeeIds)
    {
        $contactEmployee = make(WorkContactEmployeeContract::class);

        $res = $contactEmployee->countWorkContactEmployeesByEmployee($employeeIds);
        if (empty($res)) {
            return [];
        }

        return array_column($res, null, 'employee_id');
    }

    private function createQrCode(int $corpId, int $channelCodeId, array $wxUserId, bool $skipVerify)
    {
        $config = [
            'skip_verify' => $skipVerify,
            'state' => 'channelCode-' . (string) $channelCodeId,
            'user' => $wxUserId,
        ];

        $weWorkContactApp = make(WeWorkFactory::class)->getContactApp($corpId);
        $channelCodeService = make(ChannelCodeContract::class);
        $qrCodeRes = $weWorkContactApp->contact_way->create(2, 2, $config);
        if ($qrCodeRes['errcode'] !== 0) {
            $channelCodeService->deleteChannelCode($channelCodeId);
            throw new CommonException(ErrorCode::INVALID_PARAMS, sprintf('创建二维码失败，错误信息：%s', $this->getErrMsg($qrCodeRes)));
        }

        $channelCodeService->updateChannelCodeById($channelCodeId, [
            'qrcode_url' => $qrCodeRes['qr_code'],
            'wx_config_id' => $qrCodeRes['config_id'],
        ]);
    }

    private function updateQrCode(int $corpId, int $channelCodeId, array $wxUserId, bool $skipVerify, string $wxConfigId)
    {
        $config = [
            'skip_verify' => $skipVerify,
            'state' => 'channelCode-' . (string) $channelCodeId,
            'user' => $wxUserId,
        ];

        $weWorkContactApp = make(WeWorkFactory::class)->getContactApp($corpId);
        $qrCodeRes = $weWorkContactApp->contact_way->update($wxConfigId, $config);
        if ($qrCodeRes['errcode'] !== 0) {
            throw new CommonException(ErrorCode::INVALID_PARAMS, sprintf('请求微信服务器更新二维码失败，错误信息：%s', $this->getErrMsg($qrCodeRes)));
        }
    }

    /**
     * 获取错误.
     *
     * @return string
     */
    private function getErrMsg(array $res)
    {
        switch ((int) $res['errcode']) {
            case 40098:
                $errMsg = '选择成员中含有未实名认证的';
                break;
            case 84074:
                $errMsg = '选择成员中含有没有外部联系人权限的';
                break;
            default:
                $errMsg = $res['errmsg'];
                break;
        }

        return $errMsg;
    }
}
